//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FpsSceneManager.h"

#include "ParticleSystem/IFpsParticleSystemSceneNode.h"
#include "ParticleSystem/CFpsParticleSystemSceneNode.h"

#include "IrrCompileConfig.h"
#include "IVideoDriver.h"
#include "IMaterialRenderer.h"
#include "CColladaDatabase.h"
#include "CCameraSceneNode.h"
//#include "os.h"

#include "Core/Commons.h"

#include "CColladaMeshSceneNode.h"
#include "COctTreeTriangleSelector.h"
#include "EMaterialTypes.h"

#include "CColladaSkinnedMeshSceneNode.h"
#include "CSceneCollisionManager.h"

#include "Game/Level/Level.h"
#include "Game/Entities/Player.h"
#include "Game/Rooms/Room.h"

#include "Game/Entities/Player.h"
#include "Game/Utils/Utils.h"
#include "FpsMaterial.h"

#include "Application.h"
#include "FpsSkyBoxSceneNode.h"
#include "FpsCommonGLMaterialRenderer.h"
#include "CColladaMesh.h"

#include "GameSettings.h"
#include "Common/Profile.h"

#include "Lib2D/UIInfo.h"

#if USE_TIME_PROFILE
#	include <OpenGLES/ES1/gl.h>
#	include <OpenGLES/ES1/glext.h>
#endif //USE_TIME_PROFILE

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;

int __dbg_counter = 0;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define DEBUG_STATISTICS


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CMySceneCollisionManagerEx : public irr::scene::CSceneCollisionManager
{
public:
	//! constructor
	CMySceneCollisionManagerEx(ISceneManager* smanager, video::IVideoDriver* driver):CSceneCollisionManager(smanager, driver)
	{
		m_pSmanager = smanager;
		m_pDriver = driver;
	}

		//! destructor
	virtual ~CMySceneCollisionManagerEx()
	{
	}
	virtual irr::core::position2d<s32> getScreenCoordinatesFrom3DPosition(
		irr::core::vector3df pos3d, irr::scene::ICameraSceneNode* camera=0)
	{
		if (!m_pSmanager || !m_pDriver)
		return core::position2d<s32>(-1000,-1000);

		if (!camera)
			camera = m_pSmanager->getActiveCamera();

		if (!camera)
			return core::position2d<s32>(-1000,-1000);
		
		UI_ITEM *pUiItme = UIInfo::instance()->GetUIItem( UI::Interface_DefaultResolution );
#if defined(WIN32)
		core::dimension2d<s32> dim(pUiItme->m_posX,pUiItme->m_posY);
#else
		int ww = pUiItme->m_posY;
		int hh = pUiItme->m_posX;
		if( Application::instance()->IsLoadHighQuality() )
		{
			ww *= 2;
			hh *= 2;
		}
		core::dimension2d<s32> dim(ww,hh);
#endif

		dim.Width /= 2;
		dim.Height /= 2;

		core::matrix4 trans = camera->getProjectionMatrix();
		trans *= camera->getViewMatrix();

		f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f };

		trans.multiplyWith1x4Matrix(transformedPos);

		if (transformedPos[3] < 0)
			return core::position2d<s32>(-10000,-10000);

		const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f :
			core::reciprocal(transformedPos[3]);

		s32 rx = core::round32(dim.Width * transformedPos[0] * zDiv) + dim.Width;
		s32 ry = dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv));
		m_pDriver->Orientation3D_Internal2ScreenPos(rx, ry);
		
#if !defined(WIN32)
		if( Application::instance()->IsLoadHighQuality() )
		{
			rx /= 2;
			ry /= 2;
		}
#endif
		return core::position2d<s32>(rx, ry);
	}

private:
	irr::scene::ISceneManager* m_pSmanager;
	irr::video::IVideoDriver* m_pDriver;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CFpsSceneManager::CFpsSceneManager(irr::video::IVideoDriver* Driver, irr::io::IFileSystem* fs,
		irr::gui::ICursorControl* cursorControl, irr::scene::IMeshCache* cache,
		irr::gui::IGUIEnvironment *guiEnvironment) :
	CSceneManager(Driver, fs, cursorControl, cache, guiEnvironment)
{
	SpidermanShadow_RTT = 0;

	if (CollisionManager)
		CollisionManager->drop();

	CollisionManager = irrnew CMySceneCollisionManagerEx(this, Driver);
}

CFpsSceneManager::~CFpsSceneManager()
{	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//! registers a node for rendering it at a specific time.

	irr::scene::ISceneNode* __testSceneNode = 0;
int getNumbersOfChildren(ISceneNode* node)
{
	int result = node->getChildren().getSize();
	for (core::list<ISceneNode*>::ConstIterator it = node->getChildren().begin(); it != node->getChildren().end(); ++it) {
		result += getNumbersOfChildren(*it);
	}
	return result;
}

u32 CFpsSceneManager::registerNodeForRendering(ISceneNode* node,
											const video::SMaterial* material,
											void* renderData,
											E_SCENE_NODE_RENDER_PASS time,
											const core::vector3df* absPos,
											int layer)
{
	Profile("register", "reg cull");////temp 
	u32 taken = 0;
	int rndlayer = node->getRenderingLayer();

	if(rndlayer > 0)
	{
		switch(rndlayer)
		{
			case RL_SKINSHADOW:
		#ifndef USE_RTT_SHADOW
			case RL_SPIDERMAN_SHADOW_MESH:
		#endif
			{
				if (!isCulled(node))
				{	
					SkinnedShadows.push_back(SFpsDefaultNodeEntry(node, material, renderData));
					taken = 1;
				}
				break;
			}

		#ifdef USE_RTT_SHADOW
			case RL_SPIDERMAN_SHADOW_MESH:
				SpidermanShadow_RTT = node;
				taken = 1;
				break;
		#endif

			case 888:
			{
			#ifdef USE_RTT_SHADOW
				//if (!isCulled(node))
				{
					ShadowNodeList2.push_back(SFpsDefaultNodeEntry(node, material, renderData));
					taken = 1;
				}
			#endif
				break;
			}

			case RL_SPIDERMAN:
				if (PROFILE_SETTING.m_bOutline)
				{
					OutlineCharactersNodes.push_back(SFpsDefaultNodeEntry(node, material, renderData));
					//SetMaterialThickness(node, 3.0f);
				//	{
				//		irr::collada::CSkinnedMeshSceneNode* n2 = (irr::collada::CSkinnedMeshSceneNode*)node;
				//		n2->m_bEnableOutline = true;
				//	}
				}

			case RL_SKINCHARACTERS:
				if (!isCulled(node))
				{
					irr::collada::CSkinnedMeshSceneNode* n = (irr::collada::CSkinnedMeshSceneNode*)node;
					CColladaSkinnedMesh* m = (CColladaSkinnedMesh*)n->getMesh();
					m->EnableMultipleCaching(true);

					SkinnedCharactersNodes.push_back(SFpsDefaultNodeEntry(node, material, renderData));
					taken = 1;
				}
				break;

			case RL_HIT_EFFECTS:
				HitEffects.push_back(SFpsDefaultNodeEntry(node, material, renderData));
				taken = 1;
				break;

			case RL_MIRRORS:
				if (!isCulled(node))
				{
					Mirrors.push_back(node);
					taken = 1;
				}
				break;
/*
			case RL_HIGHLIGHT:
				if (!isCulled(node))
				{
					HighlightNodes.push_back(node);
					node->setRenderingLayer(0);
					taken = 1;
				}
				break;
*/
			case RL_WINDOWS:
				if (!isCulled(node))
				{
					f32 distance = node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(CamWorldPos) + node->getCameraOffset();
					WindowsNodes.push_back(SReflectingWindowNodeEntry(node, renderData, distance));
					taken = 1;
				}
				break;
		}
	}
	else
	{
		switch(time)
		{
			// take camera if it doesn't exists
			case ESNRP_CAMERA:
			{
				taken = 1;
				for ( u32 i = 0; i != CameraList.size(); ++i )
				{
					if ( CameraList[i].Node == node )
					{
						taken = 0;
						break;
					}
				}
				if ( taken )
				{
					CameraList.push_back(SUnsortedNodeEntry(node, renderData));
				}
			}
			break;

		case ESNRP_LIGHT:
			// TODO: Point Light culling..
			// Lighting modell in irrlicht has to be redone..
			//if (!isCulled(node))
			{/*
				LightList.push_back(SDistanceNodeEntry(node, CamWorldPos, renderData));
				taken = 1;*/
			}
			break;

		case ESNRP_SKY_BOX:
			SkyBoxList.push_back(SUnsortedNodeEntry(node, renderData));
			taken = 1;
			break;

		case ESNRP_SOLID:
			if (!isCulled(node))
			{
				SolidNodeList2.push_back(SFpsDefaultNodeEntry(node, material, renderData));
				taken = 1;
			}
			break;

		case ESNRP_TRANSPARENT:
			if (!isCulled(node))
			{
				if(material && material->getMaterialTypeParam(2) == FPS_MATERIAL_RENDER_PRIORITY_GROUND_TRANSPARENT)
				{
					SolidNodeList2.push_back(SFpsDefaultNodeEntry(node, material, renderData));
				}
				else
				{
					TransparentNodeList.push_back(STransparentNodeEntry(node,
																		CamWorldPos,
																		material,
																		renderData,
																		absPos,
																		layer));
				}
				taken = 1;
			}
			break;

		case ESNRP_AUTOMATIC:
			if (!isCulled(node))
			{
				taken = 1;
				if (material && material->getMaterialTypeParam(2) != FPS_MATERIAL_RENDER_PRIORITY_GROUND_TRANSPARENT)
				{
					video::IMaterialRenderer* rnd =
						Driver->getMaterialRenderer(material->getMaterialType());
					if (rnd && rnd->isTransparent() && !IsTransparentPassRegisteredAsSolid)
					{
						TransparentNodeList.push_back(STransparentNodeEntry(node,
																			CamWorldPos,
																			material,
																			renderData,
																			absPos,
																			layer));
						break;
					}
				}
				SolidNodeList2.push_back(SFpsDefaultNodeEntry(node, material, renderData));
			}
			break;

		case ESNRP_SHADOW:
			if (!isCulled(node))
			{
				ShadowNodeList.push_back(SUnsortedNodeEntry(node, renderData));
				taken = 1;
			}
			break;

		case ESNRP_COUNT: // ignore this one
			break;
		}
	}

	return taken;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! This method is called just before the rendering process of the whole scene.
//! draws all scene nodes
void CFpsSceneManager::drawAll(ISceneNode* root)
{
	if (!Driver)
		return;

	// reset attributes
// 	Parameters.setAttribute ( "culled", (s32)0 );
//	Parameters.setAttribute ( "calls", (s32)0 );
	Parameters.setAttribute ( "drawn", (s32)0 );
// 	Parameters.setAttribute ( "bindings", (s32)0 );
// 	Parameters.setAttribute ( "drawcalls", (s32)0 );

	// reset all transforms
//#endif

#ifdef _IRR_IDENTITY_MATRIX_INITIALIZATION_PER_FRAME_
	Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_TEXTURE_0, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_TEXTURE_1, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_TEXTURE_2, core::IdentityMatrix );
	Driver->setTransform ( video::ETS_TEXTURE_3, core::IdentityMatrix );
#endif

	Driver->setOption(video::EVDO_ALLOW_ZWRITE_ON_TRANSPARENT,
					  Parameters.getAttributeAsBool( ALLOW_ZWRITE_ON_TRANSPARENT) );

#ifdef _IRR_ENABLE_SCENE_OPTIMIZED_TRAVERSAL
	if (root)
	{
		RenderableNodeList.set_used(0);
		AnimatorNodeList.set_used(0);
		collectAllNodes(root);
		HierarchyChanged = false;
		((CFpsSceneManager*)SceneManager)->OnRegisterSceneNode();
		HierarchyChanged = true;
	}/*
	else if (HierarchyChanged)
	{
		collectAllNodes();
	}*/
#endif // _IRR_ENABLE_SCENE_OPTIMIZED_TRAVERSAL

	/*!
		First Scene Node for prerendering should be the active camera
		consistent Camera is needed for culling
	*/
	CamWorldPos.set(0,0,0);
	if (ActiveCamera)
	{
		ActiveCamera->OnRegisterSceneNode();		
		CamWorldPos = ActiveCamera->getAbsolutePosition();
	}

	{
		Profile("register", "reg all");////temp 
		// let all nodes register themselves
		(root ? root : this)->OnRegisterSceneNode();
	}

	s32 i; // new ISO for scoping problem in some compilers

	/////////////////////////////////////////////////////////////////

	#ifdef USE_RTT_SHADOW
		if(SpidermanShadow_RTT)
		{
			CurrentRendertime = ESNRP_SOLID;
			Player* p = CLevel::instance()->GetPlayer();
			
			Driver->setTransform ( video::ETS_PROJECTION, p->m_pShadow->m_rttProjection );
			Driver->setTransform ( video::ETS_VIEW, p->m_pShadow->m_rttView );

			irr::video::ITexture* rt = p->m_pShadow->m_pRT;
			Driver->setClearColor(irr::video::SColor(0, 0, 0, 0));
			Driver->setRenderTarget(rt);
			
			SpidermanShadow_RTT->render((void*)1);

			Driver->setClearColor(irr::video::SColor(0, 0, 0, 0));
			Driver->setRenderTarget(0);
			p->m_pShadow->m_pShadowPlane->setPosition(p->GetSteadyPos() + vector3df(-200.0f, 150.0f, 0.0f));	//junk
		}
	#endif

	/////////////////////////////////////////////////////////////////
	
	//render camera scenes
	{
		//Profile("draw", "renderCamera");
		CurrentRendertime = ESNRP_CAMERA;
		for (i=0; i<CameraList.size(); ++i)
			CameraList[i].Node->render(CameraList[i].RenderData);

		CameraList.set_used(0);
	}
	
	//render lights scenes
	{/*
		//Profile("draw", "renderLights");
		CurrentRendertime = ESNRP_LIGHT;

		Driver->deleteAllDynamicLights();

		Driver->setAmbientLight(AmbientLight);

		LightList.sort();		// on distance to camera

		u32 maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), LightList.size() );
		for (i=0; i< maxLights; ++i)
			LightList[i].Node->render(LightList[i].RenderData);

		LightList.set_used(0);
		*/
	}
	glDisable(GL_ALPHA_TEST);

	{
		//Profile("draw", "Mirrors");
	// Render mirrors
	if (Mirrors.size() || WindowsNodes.size())
	{
		for (i=0; i < SkyBoxList.size(); ++i)
			((FpsSkyBoxSceneNode *) SkyBoxList[i].Node)->renderMirror();

		for (i = 0; i < Mirrors.size(); ++i)
		{
			CColladaMeshSceneNode *MNode		= (CColladaMeshSceneNode *) Mirrors[i];
			collada::CRootSceneNode *MSceneNode	= (collada::CRootSceneNode *) MNode->GetRoot();
			const matrix4 &MirrorMatrix			= MSceneNode->getAbsoluteTransformation();

			vector3df PlanePosition(MirrorMatrix[12], MirrorMatrix[13], MirrorMatrix[14]);
			vector3df PlaneNormal(MirrorMatrix[1], MirrorMatrix[5], MirrorMatrix[9]);
			PlaneNormal.normalize();

			matrix4 reflexion;
			matrix4 transform;
			reflexion.buildReflexionMatrix(plane3df(PlanePosition, PlaneNormal));

			vector3df cameraCenter = getActiveCamera()->getAbsolutePosition();
			aabbox3df mirrorBBox   = Mirrors[i]->getTransformedBoundingBox();

			vector3df vertices[8];
			bool	  bInMirror;

			//* Render mirrored characters
			for (int j=0; j<SkinnedCharactersNodes.size(); ++j)
			{
				collada::CSkinnedMeshSceneNode* Node	= (collada::CSkinnedMeshSceneNode*)SkinnedCharactersNodes[j].Node;
				collada::CRootSceneNode *SceneNode		= (collada::CRootSceneNode *) Node->GetRoot();
				SMaterial  &NodeMaterial				= Node->getMaterial(0);
				matrix4 original						= SceneNode->getAbsoluteTransformation();
				aabbox3df charBBox						= Node->getTransformedBoundingBox();

				transform = reflexion;
				transform *= original;

				reflexion.transformBox(charBBox);
				charBBox.getEdges(vertices);
			
				bInMirror = false;
				for (int k = 0; k < 8; ++k)
				{
					if (mirrorBBox.intersectsWithLine(line3df(cameraCenter.X, cameraCenter.Y, cameraCenter.Z, vertices[k].X, vertices[k].Y, vertices[k].Z)))
					{
						bInMirror = true;
						break;
					}
				}

				if (!bInMirror)
					continue;

				SceneNode->setAbsoluteTransformation(transform);
				SceneNode->OnAnimate(0);

				NodeMaterial.setFlag(EMF_BACK_FACE_CULLING, false);
				NodeMaterial.setFlag(EMF_FRONT_FACE_CULLING, true);

				CColladaSkinnedMesh* MeshNode = (CColladaSkinnedMesh*) Node->getMesh();

				MeshNode->EnableMultipleCaching(false);
				Node->render((void *) 1);
				MeshNode->EnableMultipleCaching(true);

				NodeMaterial.setFlag(EMF_BACK_FACE_CULLING, true);
				NodeMaterial.setFlag(EMF_FRONT_FACE_CULLING, false);

				SceneNode->setAbsoluteTransformation(original);
				SceneNode->OnAnimate(0);
			}
			//*/
		}

		//* Clear the depth buffer
		//Driver->clearBuffers(EFB_DEPTH);
		//*/

		Driver->setOption(EVDO_ALLOW_ZWRITE_ON_TRANSPARENT, true);
		for (i = 0; i < Mirrors.size(); i++)
		{
			Mirrors[i]->setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL_REF_BLEND);
			Mirrors[i]->render((void *) 1);
		}

		//* Render transparent/reflecting windows
		WindowsNodes.sort(); // sort by distance from camera
		
		for (i=0; i < WindowsNodes.size(); ++i)
		{
			E_MATERIAL_TYPE OriginalType = WindowsNodes[i].Node->getMaterial(0).getMaterialType();

			SetMaterialType(WindowsNodes[i].Node, EMT_TRANSPARENT_ALPHA_CHANNEL);
			WindowsNodes[i].Node->render(WindowsNodes[i].RenderData);
			SetMaterialType(WindowsNodes[i].Node, OriginalType);
		}
		//*/

		Driver->setOption(EVDO_ALLOW_ZWRITE_ON_TRANSPARENT, false);
	}
	}

	// render skyboxes
	if(SkyBoxList.size()>0)
	{
		Profile("draw", "skyBox");////temp 
		CurrentRendertime = ESNRP_SKY_BOX;

		if( getActiveCamera() )
		{
			float zFar = getActiveCamera()->getFarValue();
			getActiveCamera()->setFarValue(16000);
			Driver->setTransform(ETS_PROJECTION, getActiveCamera()->getProjectionMatrix());

			for (i=0; i < SkyBoxList.size() && i < 1; ++i)
			{
				SkyBoxList[i].Node->render(SkyBoxList[i].RenderData);
			}

			//*
			getActiveCamera()->setFarValue(zFar);
			Driver->setTransform(ETS_PROJECTION, getActiveCamera()->getProjectionMatrix());
			//*/
		}
	}

	{
		Profile("draw", "TerrainNodes");////temp 
		for (i = 0; i < TerrainNodes.size(); ++i)
		{
			if(TerrainNodes[i].Material->getMaterialTypeParam(2) == FPS_MATERIAL_RENDER_PRIORITY_GROUND_TRANSPARENT)
			{
				CurrentRendertime = ESNRP_TRANSPARENT;
			}

			TerrainNodes[i].Node->render(TerrainNodes[i].RenderData);
			CurrentRendertime = ESNRP_SOLID;
		}
	}
	glDisable(GL_ALPHA_TEST);
	// render default objects
	{
		Profile("draw", "renderSolidNodeList");////temp 
		Driver->setOption(video::EVDO_RETAIN_BATCH_ON_MISS, true);

		CurrentRendertime = ESNRP_SOLID;
		SolidNodeList2.sort(); // sort by textures

		for (i=0; i<SolidNodeList2.size(); ++i)
		{
			if(SolidNodeList2[i].Material)
			{
				if(SolidNodeList2[i].Material->getMaterialTypeParam(2) == FPS_MATERIAL_RENDER_PRIORITY_GROUND_TRANSPARENT)
				{
					CurrentRendertime = ESNRP_TRANSPARENT;
				}
			}

			SolidNodeList2[i].Node->render(SolidNodeList2[i].RenderData);

			CurrentRendertime = ESNRP_SOLID;


			//u32 nodeType = (u32)SolidNodeList2[i].Node->getType();
			//LOG("global", "%d - %c%c%c%c", i, (nodeType & 0xFF), ((nodeType >> 8) & 0xFF), ((nodeType >> 16) & 0xFF), ((nodeType >> 24) & 0xFF));
		}

		Parameters.setAttribute ( "drawn", (s32) SolidNodeList2.size() );
		Driver->setOption(video::EVDO_RETAIN_BATCH_ON_MISS, false);
	}
	
	//////////////////////////////////////////////////////////////////////////////
	
	{
		Profile("draw", "OutlineCharactersNodes");////temp 
		//outline
		for (i=0; i<OutlineCharactersNodes.size(); ++i)
		{
			break;
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_ZWRITE_ENABLE, false);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_BACK_FACE_CULLING, true);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_FRONT_FACE_CULLING, false);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_WIREFRAME, false);
			SetMaterialDiffuseColor(OutlineCharactersNodes[i].Node, irr::video::SColor(255, 0, 0, 0));
			irr::core::matrix4 mat;
			mat.setScale(irr::core::vector3df(1.1f, 1.1f, 1.1f));
			irr::core::vector3df absTran = OutlineCharactersNodes[i].Node->getAbsolutePosition();
			irr::core::matrix4 absMat = OutlineCharactersNodes[i].Node->getAbsoluteTransformation();
			absMat *= mat;
			//OutlineCharactersNodes[i].Node->setAbsoluteTransformation(absMat);
			irr::collada::CSkinnedMeshSceneNode* n2 = (irr::collada::CSkinnedMeshSceneNode*)OutlineCharactersNodes[i].Node;
			OutlineCharactersNodes[i].Node->render(OutlineCharactersNodes[i].RenderData);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_ZWRITE_ENABLE, true);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_BACK_FACE_CULLING, true);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_FRONT_FACE_CULLING, false);
			SetMaterialFlag(OutlineCharactersNodes[i].Node, EMF_WIREFRAME, false);
			SetMaterialDiffuseColor(OutlineCharactersNodes[i].Node, irr::video::SColor(255, 255, 255, 255));
		}
	}	
	
/////////////////////////////////////////////////////////////////////////////
	bool IsShowCharacters = true;
#if defined(WIN32)
	if( Application::instance()->IsDisappearSpiderMan() )
	{
		IsShowCharacters = false;
	}
#endif
	{
	Profile("draw", "SkinnedCharactersNodes");////temp 
	SkinnedCharactersNodes.sort();
	for (i=0; IsShowCharacters && i<SkinnedCharactersNodes.size(); ++i)
	{
		irr::collada::CSkinnedMeshSceneNode* n = (irr::collada::CSkinnedMeshSceneNode*)SkinnedCharactersNodes[i].Node;
		if( Application::instance()->IsInSlowMotion() )
		{
			int begin = -5;
			int end = -3;
			if (SkinnedCharactersNodes[i].Node->getRenderingLayer() == RL_SPIDERMAN)	// --- player
			{
				begin = -2;
				end = -1;
			}
			n->m_bForceTransparent = true;

			CColladaSkinnedMesh* m = (CColladaSkinnedMesh*)n->getMesh();
			m->UseCache(begin);
			SkinnedCharactersNodes[i].Node->render(SkinnedCharactersNodes[i].RenderData);	//the fake
			m->UseCache(end);
			SkinnedCharactersNodes[i].Node->render(SkinnedCharactersNodes[i].RenderData);	//the fake
		}
		n->m_bForceTransparent = false;
		if (1) {
			n->m_bEnableOutline = false;
			//scene::ISceneNode* node = n->getParent()->getParent()->getSceneNodeFromName("Bip01_Spine2");
			//n->m_center = node->getAbsolutePosition();
			SkinnedCharactersNodes[i].Node->render(SkinnedCharactersNodes[i].RenderData);
			n->m_bEnableOutline = false;
		} else {
			n->m_bEnableOutline = true;
			scene::ISceneNode* node = n->getParent()->getParent()->getSceneNodeFromName("Bip01_Spine2");
			n->m_center = node->getAbsolutePosition();
			SkinnedCharactersNodes[i].Node->render(SkinnedCharactersNodes[i].RenderData);
			n->m_bEnableOutline = false;
		}
	}	
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////


#ifdef USE_RTT_SHADOW
	PROFILE_START(308);
	CurrentRendertime = ESNRP_TRANSPARENT;
	for (i=0; i<ShadowNodeList2.size(); ++i)
		ShadowNodeList2[i].Node->render((void*)1);

	ShadowNodeList2.set_used(0);
	PROFILE_STOP(308);
#endif

	// don't render Highlight Nodes when compiling
	if (root == NULL)
	{
		//* Render highlighted objects
		matrix4 Original;
		matrix4 Transform = IdentityMatrix;

		Transform[ 0] += 0.2f;
		Transform[ 5] += 0.2f;
		Transform[10] += 0.1f;

		for (i = 0; i < HighlightNodes.size(); ++i)
		{
			SMaterial &Material					= HighlightNodes[i]->getMaterial(0);
			aabbox3df BBox						= HighlightNodes[i]->getTransformedBoundingBox();
			Original							= HighlightNodes[i] ->getAbsoluteTransformation();
			float HalfHeight					= (BBox.MaxEdge.Z - BBox.MinEdge.Z) * 0.5f;
			Transform[14]						= -Transform[10] * HalfHeight + HalfHeight;
			E_MATERIAL_TYPE OriginalType		= Material.getMaterialType();
		
			matrix4 m = Original * Transform;
			HighlightNodes[i]->setAbsoluteTransformation(m);
			HighlightNodes[i]->OnAnimate(0);


			Material.setFlag(EMF_ZWRITE_ENABLE, false);
			Material.setMaterialType(EMT_AMBIENT_COLOR_TEXTURE_ALPHA);
			Material.setAmbientColor(SColor(0, 255, 70, 0));

			HighlightNodes[i]->render((void*) 1);

			Material.setFlag(EMF_ZWRITE_ENABLE, true);
			HighlightNodes[i]->setAbsoluteTransformation(Original);
			HighlightNodes[i]->OnAnimate(0);

			Material.setMaterialType(OriginalType);
		}

		for (i = 0; i < HighlightNodes.size(); ++i)
			HighlightNodes[i]->render((void*) 1);
	}
	
	//	Driver->setOption(video::EVDO_ALLOW_ZWRITE_ON_TRANSPARENT, true );

	// render transparent objects.
	{
		Profile("draw", "renderTransparent");////temp 
		CurrentRendertime = ESNRP_TRANSPARENT;
		TransparentNodeList.sort(); // sort by distance from camera

		for (i=0; i<TransparentNodeList.size(); ++i)
		{
			TransparentNodeList[i].Node->render(TransparentNodeList[i].RenderData);
		}
	}	

	/////////////////////////////////////////////////////////////////////////

	//Draw__TestNodes();	
	{
		Profile("draw", "HitEffects");////temp 
		for (i = 0; i < HitEffects.size(); ++i)
			HitEffects[i].Node->render(HitEffects[i].RenderData);
	}

	if (SkinnedShadows.size())
	{
		Profile("draw", "renderSkinnedShadows");////temp 
		
		//* Shadows prototype. Render shadows depth/mask
		Driver->setClearDepth(0.0f);
		Driver->clearBuffers(EFB_DEPTH);
		Driver->setClearDepth(1.0f);
	
		//* Properly adjust far plane for shadows rendering
		float zFar = getActiveCamera()->getFarValue();
		getActiveCamera()->setFarValue(7000);
		Driver->setTransform(ETS_PROJECTION, getActiveCamera()->getProjectionMatrix());
		//*/

		matrix4 originalView = Driver->getTransform(ETS_VIEW);
		matrix4 originalProj = Driver->getTransform(ETS_PROJECTION);

		for (i = 0; i < SkinnedShadows.size(); i++)
		{
			collada::CSkinnedMeshSceneNode *SkinnedShadowNode	= (collada::CSkinnedMeshSceneNode *) SkinnedShadows[i].Node;
			collada::CRootSceneNode *ShadowRootNode				= (collada::CRootSceneNode *) SkinnedShadowNode->GetRoot();
			matrix4 *ShadowMatrix								= (matrix4*) ShadowRootNode->getGameData();

			if (ShadowMatrix)
			{
				matrix4 newView	= originalView * (*ShadowMatrix);
				Driver->setTransform(ETS_VIEW, newView);
				SkinnedShadows[i].Node->render(SkinnedShadows[i].RenderData);
			}
		}
		
		//*
		getActiveCamera()->setFarValue(zFar);
		Driver->setTransform(ETS_PROJECTION, getActiveCamera()->getProjectionMatrix());
		//*/
		
		//* Render shadows color
		SMaterial	Material;
		S3DVertex	QuadVertices[4];
		u16			QuadIndices[6] = {0, 1, 2, 1, 2, 3};

		QuadVertices[0] = S3DVertex(-1.0f, +1.0f, -0.99f, 0,0,0, SColor(70, 0, 0, 0), 0.0f, 0.0f);
		QuadVertices[1] = S3DVertex(-1.0f, -1.0f, -0.99f, 0,0,0, SColor(70, 0, 0, 0), 0.0f, 0.0f);
		QuadVertices[2] = S3DVertex(+1.0f, +1.0f, -0.99f, 0,0,0, SColor(70, 0, 0, 0), 0.0f, 0.0f);
		QuadVertices[3] = S3DVertex(+1.0f, -1.0f, -0.99f, 0,0,0, SColor(70, 0, 0, 0), 0.0f, 0.0f);

		Material.setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL);
		Material.setFlag(EMF_LIGHTING, false);
		Material.setFlag(EMF_ZBUFFER, true);
		Material.setFlag(EMF_ZWRITE_ENABLE, false);

		Driver->setTransform(ETS_WORLD, IdentityMatrix);
		Driver->setTransform(ETS_VIEW, IdentityMatrix);
		Driver->setTransform(ETS_PROJECTION, IdentityMatrix);

		Driver->setMaterial(Material);
		Driver->drawVertexPrimitiveList(QuadVertices, QuadIndices, 0, 4, 4, EVT_STANDARD, EPT_TRIANGLE_STRIP, EIT_16BIT);

		Driver->setTransform(ETS_VIEW, originalView);
		Driver->setTransform(ETS_PROJECTION, originalProj);				
	}

	clearDeletionList();
	clearRenderLists();

	CurrentRendertime = ESNRP_COUNT;

#ifdef DEBUG_STATISTICS
	// Write and reset stats
	//Stats.reset(&Parameters);
#endif
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void CFpsSceneManager::clearRenderLists()
{
	CameraList.set_used(0);
	SkyBoxList.set_used(0);
	LightList.set_used(0);
	SolidNodeList2.set_used(0);
	TransparentNodeList.set_used(0);

	HitEffects.set_used(0);
	SkinnedShadows.set_used(0);
	TerrainNodes.set_used(0);
	ShadowNodeList2.set_used(0);
	SkinnedCharactersNodes.set_used(0);
	OutlineCharactersNodes.set_used(0);
	Mirrors.set_used(0);
	HighlightNodes.set_used(0);
	WindowsNodes.set_used(0);
	
	__TestNodes.set_used(0);

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//! Adds a particle system scene node.

IFpsParticleSystemSceneNode* CFpsSceneManager::addFpsParticleSystemSceneNode(
	bool withDefaultEmitter, ISceneNode* parent, s32 id,
	const core::vector3df& position, const core::vector3df& rotation,
	const core::vector3df& scale)
{
	if (!parent)
		parent = this;

	IFpsParticleSystemSceneNode* node = irrnew CFpsParticleSystemSceneNode(withDefaultEmitter,
		id, position, rotation, scale);
	parent->addChild(node);

	node->drop();

	return node;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void CFpsSceneManager::Draw__TestNodes()
{
	int i;

	for (i=0; i<__TestNodes.size(); ++i)
		__TestNodes[i].Node->render(__TestNodes[i].RenderData);

	__TestNodes.set_used(0);
}



irr::scene::ISceneCollisionManager* CFpsSceneManager::getSceneCollisionManager()
{
	return CollisionManager;
}

